package cfgpltfm

import (
	"context"
	"fmt"
	"sync"
	"time"

	"gitee.com/MikeDDD/gu/cfgpltfm/cfgpltrpcpb"
	"gitee.com/MikeDDD/gu/guutil"
	"gitee.com/MikeDDD/gu/logs"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

type CfgpltfmClient struct {
	cfgpltAddr string
	selfAddr   string
	env        string
	keyHandler sync.Map // map["key_camp"]func(*cfgpltrpcpb.GetResp)
	cfgpltrpcpb.UnimplementedCfgpltClientRpcServer
}

func New(cfgpltAddr, selfAddr, env string) *CfgpltfmClient {
	cli := &CfgpltfmClient{
		cfgpltAddr: cfgpltAddr,
		selfAddr:   selfAddr,
		env:        env,
	}

	return cli
}

// 客户端 => 中心 心跳
func (cli *CfgpltfmClient) Ping() bool {
	defer guutil.InDeferRecover()

	conn, err := grpc.Dial(cli.cfgpltAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		logs.Error(err)
		return false
	}
	defer conn.Close()

	client := cfgpltrpcpb.NewCfgpltServiceRpcClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	if _, err := client.Regist(ctx, &cfgpltrpcpb.RegistReq{
		ClientAddr: cli.selfAddr,
		Env:        cli.env,
	}); err != nil {
		logs.Error(err)
		return false
	}

	return true
}

// 客户端 => 中心 请求
func (cli *CfgpltfmClient) Get(key string, camp int32) *cfgpltrpcpb.GetResp {
	defer guutil.InDeferRecover()

	conn, err := grpc.Dial(cli.cfgpltAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		logs.Error(err)
		return nil
	}
	defer conn.Close()

	client := cfgpltrpcpb.NewCfgpltServiceRpcClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
	defer cancel()

	resp, err := client.Get(ctx, &cfgpltrpcpb.GetReq{Key: key, Camp: camp})
	if err != nil {
		logs.Error(err)
		return nil
	}

	udata, ok := guutil.GzipBase64Unmarshall(resp.Value)
	if !ok {
		logs.Error("unmarshall fail")
		return nil
	}
	resp.Value = udata

	return resp
}

// 客户端 => 中心 请求
func (cli *CfgpltfmClient) GetAndWatch(key string, camp int32, callback func(*cfgpltrpcpb.GetResp)) bool {
	defer guutil.InDeferRecover()

	resp := cli.Get(key, camp)
	if resp == nil {
		return false
	}

	cli.keyHandler.Store(fmt.Sprintf("%v_%v", key, camp), callback)

	callback(resp)

	return true
}

// 中心 => 客户端
func (cli *CfgpltfmClient) Push(ctx context.Context, req *cfgpltrpcpb.PushReq) (*cfgpltrpcpb.PushResp, error) {
	if req.Env != cli.env {
		logs.Info("skip env %v, self %v", req.Env, cli.env)
		return &cfgpltrpcpb.PushResp{}, nil
	}

	callback, exist := cli.keyHandler.Load(fmt.Sprintf("%v_%v", req.Key, req.Camp))
	if !exist {
		logs.Warn("no handler for %v", fmt.Sprintf("%v_%v", req.Key, req.Camp))
		return &cfgpltrpcpb.PushResp{}, nil
	}

	udata, ok := guutil.GzipBase64Unmarshall(req.Value)
	if !ok {
		logs.Error("unmarshall fail")
		return &cfgpltrpcpb.PushResp{}, nil
	}

	callback.(func(*cfgpltrpcpb.GetResp))(&cfgpltrpcpb.GetResp{
		Key:   req.Key,
		Camp:  req.Camp,
		Value: udata,
	})

	return &cfgpltrpcpb.PushResp{}, nil
}
